package com.tianji.promotion.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CategoryClient;
import com.tianji.api.dto.course.CategoryBasicDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.promotion.domain.dto.CouponFormDTO;
import com.tianji.promotion.domain.dto.CouponIssueFormDTO;
import com.tianji.promotion.domain.enums.CouponStatus;
import com.tianji.promotion.domain.enums.ObtainType;
import com.tianji.promotion.domain.enums.UserCouponStatus;
import com.tianji.promotion.domain.po.Coupon;
import com.tianji.promotion.domain.po.CouponScope;
import com.tianji.promotion.domain.po.UserCoupon;
import com.tianji.promotion.domain.query.CouponQuery;
import com.tianji.promotion.domain.query.UserCouponQuery;
import com.tianji.promotion.domain.vo.CouponDetailVO;
import com.tianji.promotion.domain.vo.CouponPageVO;
import com.tianji.promotion.domain.vo.CouponScopeVO;
import com.tianji.promotion.domain.vo.CouponVO;
import com.tianji.promotion.mapper.CouponMapper;
import com.tianji.promotion.service.ICouponScopeService;
import com.tianji.promotion.service.ICouponService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.promotion.service.IExchangeCodeService;
import com.tianji.promotion.service.IUserCouponService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.tianji.promotion.domain.enums.CouponStatus.*;

/**
 * <p>
 * 优惠券的规则信息 服务实现类
 * </p>
 *
 * @author 优惠卷模块
 * @since 2023-04-20
 */
@Service
@RequiredArgsConstructor
public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> implements ICouponService {

    private final ICouponScopeService scopeService;

    private final IExchangeCodeService codeService;

    private final CategoryClient client;

    private final IUserCouponService userCouponService;

    @Override
    public void AddCoupons(CouponFormDTO couponFormDTO) {
        //保存优惠卷
        //转PO
        Coupon coupon = BeanUtils.copyBean(couponFormDTO, Coupon.class);
        save(coupon);
        //保存
        if (!couponFormDTO.getSpecific()) {
            //保存超过范围
            return;
        }
        Long couponId = coupon.getId();
        //保存限定范围
        List<Long> scopes = couponFormDTO.getScopes();
        if (CollUtils.isEmpty(scopes)) {
            throw new BadRequestException("范围不为空");
        }
        List<CouponScope> couponScopes = scopes.stream()
                .map(bizeId -> new CouponScope().setBizId(bizeId).setCouponId(couponId)).collect(Collectors.toList());
        //范围保存
        scopeService.saveBatch(couponScopes);
    }


    /**
     * 分页查询
     *
     * @param query
     * @return
     */

    @Override
    public PageDTO<CouponPageVO> PageCoupons(CouponQuery query) {

        //获取query中的分页条件
        String name = query.getName();
        Integer status = query.getStatus();
        Integer type = query.getType();

        //分页查询
        Page<Coupon> page = lambdaQuery()
                .eq(status != null, Coupon::getStatus, status)
                .eq(type != null, Coupon::getType, type)
                .eq(StringUtils.isNotBlank(name), Coupon::getName, name)
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        //处理VO
        List<Coupon> coupons = page.getRecords();
        if (CollUtils.isEmpty(coupons)) {
            return PageDTO.empty(page);
        }
        //返回
        List<CouponPageVO> list = BeanUtils.copyList(coupons, CouponPageVO.class);
        return PageDTO.of(page, list);
    }

    /**
     * 发放优惠卷
     *
     * @param formDTO
     */
    @Override
    public void FaCoupons(CouponIssueFormDTO formDTO) {
        //查询优惠卷
        Coupon coupon = getById(formDTO.getId());

        if (coupon == null) {
            throw new BadRequestException("优惠卷不存在");
        }
        //判断优惠卷状态，是否是暂停和带发放
        if (coupon.getStatus() == PAUSE.getValue() && coupon.getStatus() == CouponStatus.DRAFT.getValue()) {
            throw new BadRequestException("优惠卷状态错误！");
        }
        //判断是否是立即发放
        LocalDateTime beginTime = formDTO.getIssueBeginTime();
        LocalDateTime now = LocalDateTime.now();

        //开始发放时间为null或者发放时间小于等于当前时间，都代表立刻发放
        boolean b = beginTime == null || !beginTime.isAfter(now);

        //拷贝属性到PO
        Coupon c = BeanUtils.copyBean(formDTO, Coupon.class);
        //更新状态
        if (b) {
            c.setStatus(CouponStatus.ISSUING.getValue());
            c.setIssueBeginTime(now);
        } else {
            c.setStatus(CouponStatus.UN_ISSUE.getValue());
        }
        //更新优惠卷
        updateById(c);

        //判断是否需要生成兑换码，优惠卷类型必须是兑换码，优惠卷状态必须是发放中
        if (coupon.getObtainWay() == ObtainType.ISSUE.getValue() && coupon.getStatus() == CouponStatus.ISSUING.getValue()) {
            coupon.setIssueEndTime(c.getIssueEndTime());
            codeService.asyncGenerateCode(coupon);
        }
    }

    /**
     * 暂停发放优惠卷
     * @param id
     */
    @Override
    public void PauseCoupons(Long id) {
        //查询旧优惠卷
        Coupon coupon = getById(id);
        if (coupon == null){
            throw new BizIllegalException("优惠劵不存在！");
        }
        //当前优惠卷状态必须是未开始或进行中
        if (coupon.getStatus() != CouponStatus.UN_ISSUE.getValue() && coupon.getStatus() != CouponStatus.ISSUING.getValue()){
            //状态不对，立即结束
            return;
        }
        //更新状态
        boolean update = lambdaUpdate()
                .eq(Coupon::getId, id)
                .set(Coupon::getStatus, PAUSE)
                .in(Coupon::getStatus, UN_ISSUE, ISSUING)
                .update();
        if(!update){
            log.error("重复暂停优惠劵!");
        }

        //删除缓存
        
    }

    /**
     * 根据id进行查询优惠卷
     *
     * @param id
     * @return
     */
    @Override
    public CouponDetailVO IdCoupons(Long id) {

        //查询优惠卷id
        Coupon coupon = getById(id);
        if (coupon == null) {
            throw new BadRequestException("优惠卷不存在!");
        }
        //判断需不需要查询业务信息
        CouponDetailVO vo = BeanUtils.copyBean(coupon, CouponDetailVO.class);
        if (!coupon.getSpecific()) {
            //为true查询业务信息
            return vo;
        }
        //进行查询业务信息
        // 查询优惠卷的关系集合
        LambdaQueryWrapper<CouponScope> lqw = new LambdaQueryWrapper<>();
        lqw.eq(CouponScope::getCouponId, coupon.getId());
        List<CouponScope> list = scopeService.list(lqw);

        // 远程获取分类信息
        List<CategoryBasicDTO> allOfOneLevel = client.getAllOfOneLevel();
        Map<Long, CategoryBasicDTO> dtoMap = allOfOneLevel.stream()
                .collect(Collectors.toMap(CategoryBasicDTO::getId, c -> c));

        // 通过遍历进行取出业关系集合中的数据
        List<CouponScopeVO> cList = new ArrayList<>();
        // 对优惠券id与业务id映射表的数据集合进行遍历
        for (CouponScope couponScope : list) {
            CouponScopeVO cs = new CouponScopeVO();
            // 根据业务id 获取分类对象
            CategoryBasicDTO categoryBasicDTO = dtoMap.get(couponScope.getBizId());

            cs.setName(categoryBasicDTO.getName());
            cs.setId(couponScope.getBizId());
            cList.add(cs);
        }

        vo.setScopes(cList);

        //将其他信息进行封装为map集合
        //进行业务信息和优惠卷信息拼接
        //返回结果
        return vo;
    }

    @Override
    public CouponDetailVO UpdateCoupons(Long id) {
        return null;
    }

    @Override
    public List<CouponVO> SaveCoupons() {
        //查询优惠卷列表
        List<Coupon> coupons = lambdaQuery()
                .eq(Coupon::getStatus, CouponStatus.ISSUING)
                .eq(Coupon::getObtainWay, ObtainType.PUBLIC)
                .list();
        if (CollUtils.isEmpty(coupons)){
           return CollUtils.emptyList();
        }
        //统计当前用户已经领取的优惠卷的信息
        List<Long> collect = coupons.stream().map(Coupon::getId).collect(Collectors.toList());
        //查询当前用户已经领取的优惠卷数量
        Long user = UserContext.getUser();
        List<UserCoupon> userCoupons = userCouponService.lambdaQuery()
                .eq(UserCoupon::getUserId, user)
                .eq(UserCoupon::getCouponId, collect)
                .list();

        //统计当前用户已经领取的优惠卷的数量
        Map<Long, Long> longMap = userCoupons.stream().collect(Collectors.groupingBy(UserCoupon::getCouponId, Collectors.counting()));

        //统计当前用户已领取但未使用的优惠卷的数量
        Map<Long, Long> longLongMap = userCoupons.stream().filter(userCoupon -> userCoupon.getStatus() == UserCouponStatus.UNUSED.getValue()).collect(Collectors.groupingBy(UserCoupon::getCouponId, Collectors.counting()));


        //封装vo结果
        List<CouponVO> list = new ArrayList<>(coupons.size());
        //遍历优惠卷列表
        for (Coupon c : coupons) {
            //拷贝PO属性到VO
            CouponVO vo = BeanUtils.copyBean(c, CouponVO.class);
            list.add(vo);
            //是否可以领取,且已领取的数量 < 优惠卷总数量 && 当前用户已领取的数量 < 每人限领数量
            vo.setAvailable(c.getIssueNum() < c.getTotalNum() && longMap.getOrDefault(c.getId(),0L) > 0);
        }
     return list;
    }


}
